﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Web.ModelBinding;
using System.Web;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Linq.Expressions;
using System.Web.Script.Serialization;
using System.Net;
using MyBlog.Model;

namespace MyBlog.Common
{
    /// <summary>
    /// 定义了一系列拓展方法和公共静态方法
    /// </summary>
    public static class ExtensionMethod
    {
        /// <summary>
        /// 特殊字符集
        /// </summary>
        static string[] _specialCodes = { "'", "<", ">", "%", "\"\"", ",", ">=", "=<", "_", ";", "||", "[", "]", "&", "/", "|", " ", };

        /// <summary>
        /// 对象间的简单转换,只适合同类型同名称属性的转化，支持对象嵌套Class、泛型。
        /// 自己写的哦，哈哈，垃圾也要装逼一下，要是能改进像AutoMapper那样就好了，
        /// 想想那个不是自己能比的，不管怎样，just do it！try my best！
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="source"></param>
        /// <param name="isDTO"></param>
        /// <returns></returns>
        public static TResult ConvertObject<TSource, TResult>(this TSource source, bool isDTO = true) where TResult : new()
        {
            try
            {
                var sourceAttrs = typeof(TSource).GetProperties().Where(x => x.CanRead);
                var targetAttrs = typeof(TResult).GetProperties().Where(x => x.CanWrite);
                if (null == sourceAttrs || null == targetAttrs)
                {
                    return default(TResult);
                }
                TResult target = new TResult();
                foreach (var t in targetAttrs)
                {
                    foreach (var s in sourceAttrs)
                    {
                        if (s.PropertyType == t.PropertyType || s.PropertyType.Name == "String")
                        {
                            if (s.Name.Equals(t.Name))
                            {
                                t.SetValue(target, s.GetValue(source));
                                continue;
                            }
                        }
                        else if (s.PropertyType.IsClass && !s.PropertyType.IsGenericType)
                        {
                            #region 如果是类，思考怎么复制，自己写的属性命名规则，遵循这个规则就能转换，汗，麻烦也实现了，哈哈，就当尝试 -- by 2015-9-24
                            var tarCname = isDTO ? (s.PropertyType.Name.Replace("Tbl_", "") + "Model") : ("Tbl_" + s.PropertyType.Name.Replace("Model", ""));
                            var p = targetAttrs.FirstOrDefault(x => x.PropertyType.Name == tarCname);
                            if (p != null)
                            {
                                var o = Activator.CreateInstance(p.PropertyType, null);
                                foreach (var ct in o.GetType().GetProperties())
                                {
                                    foreach (var st in s.PropertyType.GetProperties())
                                    {
                                        if (ct.Name.Equals(st.Name))
                                        {
                                            if (ct.PropertyType == st.PropertyType)
                                            {
                                                ct.SetValue(o, st.GetValue(s.GetValue(source)));
                                                break;
                                            }
                                        }
                                    }
                                }
                                p.SetValue(target, o);
                                continue;
                            }
                            #endregion
                        }
                        else if (s.PropertyType.IsGenericType)
                        {
                            #region 如果是泛型类，思考怎么复制,好麻烦，但是还是想到复制的办法了，嘻嘻！
                            var sc = s.PropertyType.GetGenericArguments().First();//先获得泛型类中存放的对象类型
                            var tarCname = isDTO ? (sc.Name.Replace("Tbl_", "") + "Models") : ("Tbl_" + sc.Name.Replace("Model", ""));
                            var p = targetAttrs.FirstOrDefault(x => x.Name == tarCname);
                            if (p != null)
                            {
                                var pObjs = Activator.CreateInstance(p.PropertyType, null);
                                var pc = p.PropertyType.GetGenericArguments().First();
                                var objs = s.GetValue(source) as IEnumerable<object>;
                                if (objs != null)
                                {
                                    var add = p.PropertyType.GetMethod("Add");
                                    foreach (var ob in objs)
                                    {
                                        var rp = Activator.CreateInstance(pc, null);
                                        foreach (var r in rp.GetType().GetProperties())
                                        {
                                            foreach (var pb in ob.GetType().GetProperties())
                                            {
                                                if (r.Name.Equals(pb.Name))
                                                {
                                                    if (r.PropertyType == pb.PropertyType)
                                                    {
                                                        r.SetValue(rp, pb.GetValue(ob));
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        add.Invoke(pObjs, new object[] { rp });
                                    }
                                    p.SetValue(target, pObjs);
                                    continue;
                                }
                            }
                            #endregion
                        }
                    }
                }
                return target;
            }
            catch
            {
                return default(TResult);
            }
        }

        /// <summary>
        /// 拷贝对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <returns></returns>
        public static T Clone<T>(this T o)
        {
            BinaryFormatter bFormatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            bFormatter.Serialize(stream, o);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)bFormatter.Deserialize(stream);
        }

        /// <summary>
        /// 获取用户默认头像字节数组
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static byte[] GetDefaultHeadBytes(int width = 145, int height = 125)
        {
            try
            {
                var path = HttpContext.Current.Server.MapPath("~/Content/Images/zanwutouxiang.jpg");
                var file = new FileInfo(path);
                //var byts = new byte[file.Length];
                using (FileStream st = file.OpenRead())
                {
                    //st.Read(byts, 0, Convert.ToInt32(file.Length));
                    return st.GetImageBytes(width, height);
                }
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 返回文件的二进制字节数组,截取成对应分辨率
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static byte[] GetImageBytes(this Stream stream, int width = 145, int height = 125)
        {
            try
            {
                Bitmap bmpDest = new Bitmap(width, height);
                Bitmap bmpSrc = new Bitmap(stream);
                Graphics g = Graphics.FromImage(bmpDest);
                g.DrawImage(bmpSrc, 0, 0, bmpDest.Width, bmpDest.Height);
                using (MemoryStream ms = new MemoryStream())
                {
                    bmpDest.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                    byte[] bytes = ms.GetBuffer();
                    bmpDest.Dispose();
                    bmpSrc.Dispose();
                    g.Dispose();
                    return bytes;
                }
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 将HttpPostedFile转换成字节数组
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static byte[] FileToBytes(this HttpPostedFile file)
        {
            using (FileStream fs = new FileStream(file.FileName, FileMode.Open, FileAccess.Read))
            {
                byte[] byts = new byte[fs.Length];
                fs.Read(byts, 0, (int)fs.Length);
                return byts;
            }
        }

        /// <summary>
        /// Stream转换成字节数组
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static byte[] ToBytes(this Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        /// <summary>
        /// 将字节数组转换成Stream
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static Stream ToStream(this byte[] bytes)
        {
            using (Stream stream = new MemoryStream(bytes))
            {
                return stream;
            }
        }

        /// <summary>
        /// 获取两个时间的年月差
        /// </summary>
        /// <param name="t1"></param>
        /// <param name="t2"></param>
        /// <returns>年月字符串</returns>
        public static string YearMonthDiff(this DateTime t1, DateTime t2)
        {
            int totalMonth = t1.Year * 12 + t1.Month - t2.Year * 12 - t2.Month;
            int year = totalMonth / 12;
            return year + "年" + (totalMonth - (year * 12)) + "个月";
        }

        /// <summary>
        /// 截取指定长度的字符串，剩余长度用‘...’代替
        /// </summary>
        /// <param name="str"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string SubStr(this string str, int length)
        {
            if (string.IsNullOrWhiteSpace(str)) { return ""; }
            if (str.Length > length)
            {
                str = str.Substring(0, length) + "...";
            }
            return str;
        }

        /// <summary>
        /// 截取指定长度的字符串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string Sub(this string str, int length)
        {
            if (string.IsNullOrWhiteSpace(str)) { return ""; }
            if (str.Length > length)
            {
                str = str.Substring(0, length);
            }
            return str;
        }

        /// <summary>
        /// 格式化字符串
        /// </summary>
        /// <param name="str"></param>
        /// <param name="prms"></param>
        /// <returns></returns>
        public static string FormatStr(this string str, params object[] prms)
        {
            if (string.IsNullOrWhiteSpace(str))
            {
                return null;
            }
            return string.Format(str, prms);
        }

        /// <summary>
        /// 去除 HTML tag
        /// </summary>
        /// <param name="HTML"></param>
        /// <returns></returns>
        public static string StripHTML(this string HTML) //google "StripHTML" 得到
        {
            string[] Regexs ={
                                    @"<img[^>]*?/>",
                                    @"<script[^>]*?>.*?</script>",
                                    @"<(\/\s*)?!?((\w+:)?\w+)(\w+(\s*=?\s*(([""'])(\\[""'tbnr]|[^\7])*?\7|\w+)|.{0})|\s)*?(\/\s*)?>",
                                    @"([\r\n])[\s]+",
                                    @"&(quot|#34);",
                                    @"&(amp|#38);",
                                    @"&(lt|#60);",
                                    @"&(gt|#62);",
                                    @"&(nbsp|#160);",
                                    @"&(iexcl|#161);",
                                    @"&(cent|#162);",
                                    @"&(pound|#163);",
                                    @"&(copy|#169);",
                                    @"&#(\d+);",
                                    @"-->",
                                    @"<!--.*\n"
                                };

            string[] Replaces =
                                {
                                    "[图片]",
                                    "",
                                    "",
                                    "",
                                    "\"",
                                    "&",
                                    "<",
                                    ">",
                                    " ",
                                    "\xa1", //chr(161),
                                    "\xa2", //chr(162),
                                    "\xa3", //chr(163),
                                    "\xa9", //chr(169),
                                    "",
                                    "\r\n",
                                    ""
                                };

            string s = HTML;
            for (int i = 0; i < Regexs.Length; i++)
            {
                s = new Regex(Regexs[i], RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(s, Replaces[i]);
            }
            s.Replace("<", "");
            s.Replace(">", "");
            s.Replace("\r\n", "");
            return s;
        }

        /// <summary>
        /// 去除字符串中html标记
        /// </summary>
        /// <param name="htmlstr"></param>
        /// <returns></returns>
        public static string RemoveHtml(this string htmlstr)
        {
            var reg = new System.Text.RegularExpressions.Regex("<[^>]*>");
            var newstr = reg.Replace(htmlstr, "");
            return newstr;
        }

        /// <summary>
        /// 获取某年某月天数，主要区分闰年
        /// </summary>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <returns></returns>
        public static int GetMonthDays(int year, int month)
        {
            var bigs = new int[] { 1, 3, 5, 7, 8, 10, 12 };
            var litts = new int[] { 4, 6, 11, 9 };
            if (bigs.Contains(month))
            {
                return 31;
            }
            if (litts.Contains(month))
            {
                return 30;
            }
            if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
            {
                return 29;
            }
            return 28;
        }

        /// <summary>
        /// 返回html字符串的解码形式字符
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static string HtmlDecode(this string html)
        {
            if (!string.IsNullOrWhiteSpace(html))
            {
                return HttpUtility.HtmlDecode(html);
            }
            return null;
        }

        /// <summary>
        /// 返回字符串的html编码形式字符
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static string HtmlEncode(this string html)
        {
            if (!string.IsNullOrWhiteSpace(html))
            {
                return HttpUtility.HtmlEncode(html);
            }
            return null;
        }

        /// <summary>
        /// 对集合进行null值初始化处理
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="soures"></param>
        /// <returns></returns>
        public static IEnumerable<T> Default<T>(this IEnumerable<T> soures)
        {
            return soures ?? Enumerable.Empty<T>();
        }

        /// <summary>
        /// 忽略大小写比较两个字符串的值是否相等
        /// </summary>
        /// <param name="s1"></param>
        /// <param name="s2"></param>
        /// <returns></returns>
        public static bool Same(this string s1, string s2)
        {
            if (s1 == null || s2 == null)
            {
                return false;
            }
            //return s1.Trim().ToLower().Equals(s2.Trim().ToLower());
            return s1.Trim().Equals(s2.Trim(), StringComparison.OrdinalIgnoreCase);
        }

        public static object Cast<T>(object val)
        {
            return (T)val;
        }

        /// <summary>
        /// 过滤字符串中的特殊字符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string Filter(this string str)
        {
            if (string.IsNullOrWhiteSpace(str))
            {
                return null;
            }
            for (int i = 0; i < _specialCodes.Length; i++)
            {
                str = str.Replace(_specialCodes[i], string.Empty);
            }
            return str;
        }

        /// <summary>
        /// 过滤对象中指定属性值的特殊字符
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <param name="expProperties"></param>
        public static void Filter<T>(this T o, params Expression<Func<T, string>>[] expProperties) where T : class
        {
            try
            {
                var props = typeof(T).GetProperties().Where(x => x.CanWrite && x.PropertyType == typeof(string));
                if (expProperties == null) return;
                {
                    foreach (var p in expProperties)
                    {
                        var pro = props.FirstOrDefault(x => p.ToString().Contains(x.Name));
                        if (pro != null)
                        {
                            pro.SetValue(o, (pro.GetValue(o) as string).Filter());
                        }
                    }
                }
            }
            catch
            { }
        }

        /// <summary>
        /// 将json字符串转化为字典
        /// </summary>
        /// <param name="jsonText"></param>
        /// <returns></returns>
        public static Dictionary<string, object> JsonToDictionary(this string jsonText)
        {
            try
            {
                return new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonText);
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 发送HttpGet请求并返回响应结果
        /// </summary>
        /// <param name="url">地址</param>
        /// <param name="parms">参数列表，只支持匿名类型</param>
        /// <param name="isAppendParms">是否是直接追加参数，默认false</param>
        /// <returns></returns>
        public static string SendHttpGet(string url, dynamic parms, bool isAppendParms = false)
        {
            try
            {
                if (parms != null)
                {
                    var parmStr = string.Join("&", (parms.GetType().GetProperties() as PropertyInfo[]).Select(x => (x.Name + "=" + x.GetValue(parms))));
                    url += (isAppendParms ? "&" : "?") + parmStr;
                }
                var request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "GET";
                var response = (HttpWebResponse)request.GetResponse();
                using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    var result = reader.ReadToEnd();
                    return result;
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("发送Get请求" + url + "出错：" + ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 发送HttpPost请求并返回响应结果
        /// </summary>
        /// <param name="url">地址</param>
        /// <param name="parms">参数列表，只支持匿名类型</param>
        /// <returns></returns>
        public static string SendHttpPost(string url, dynamic parms)
        {
            try
            {
                var request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                if (parms != null)
                {
                    var parmStr = string.Join("&", (parms.GetType().GetProperties() as PropertyInfo[]).Select(x => (x.Name + "=" + x.GetValue(parms))));
                    //将URL编码后的字符串转化为字节
                    byte[] payload = System.Text.Encoding.UTF8.GetBytes(parmStr);
                    //设置请求的 ContentLength  
                    request.ContentLength = payload.Length;
                    //获得请 求流
                    using (var writer = request.GetRequestStream())
                    {
                        //将请求参数写入流
                        writer.Write(payload, 0, payload.Length);
                    }
                }
                var response = (HttpWebResponse)request.GetResponse();
                using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    var result = reader.ReadToEnd();
                    return result;
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("发送Post请求" + url + "出错：" + ex.Message);
                return null;
            }
        }

        public static string GetNoticeString(this NoticeEnum type)
        {
            string desc = null;
            switch (type)
            {
                case NoticeEnum.Register:
                    desc = "加入了小博客";
                    break;
                case NoticeEnum.AddArticle:
                    desc = "发表随笔";
                    break;
                case NoticeEnum.AddMood:
                    desc = "发表说说";
                    break;
                case NoticeEnum.AddMsg:
                    desc = "发表留言";
                    break;
                case NoticeEnum.SendMsgToSys:
                    desc = "给小博客系统留言";
                    break;
                case NoticeEnum.SendBugToSys:
                    desc = "给小博客系统提Bug";
                    break;
                case NoticeEnum.CommentArticle:
                    desc = "评论随笔";
                    break;
                case NoticeEnum.ReplyArticle:
                    desc = "回复评论";
                    break;
                case NoticeEnum.CommentMood:
                    desc = "评论说说";
                    break;
                case NoticeEnum.ReplyMsg:
                    desc = "回复留言";
                    break;
                default:
                    break;
            }
            return desc;
        }

        public static string  BuildLink(string url,string txt)
        {
            if (string.IsNullOrWhiteSpace(txt))
            {
                return null;
            }
            return "<a href='" + url + "'>" + txt.HtmlDecode().StripHTML().SubStr(100) + "</a>";
        }

    }
}
